import { unicodeRegExp } from "../../core/util/lang";
// 正则匹配
// 匹配属性 id="app" id='app' id=app
const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;
const dynamicArgAttribute = /^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+?\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;
// 匹配特殊标签名 <my-comp>
const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z${unicodeRegExp.source}]*`;
// 匹配特殊标签名 <my:comp>
const qnameCapture = `((?:${ncname}\\:)?${ncname})`;
// 匹配开始标签开始 <div
const startTagOpen = new RegExp(`^<${qnameCapture}`);
// 匹配开始标签闭合 > />
const startTagClose = /^\s*(\/?)>/;
// 匹配结束标签 </div>
const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`);
const doctype = /^<!DOCTYPE [^>]+>/i;
const comment = /^<!\--/;
const conditionalComment = /^<!\[/;

export function parseHTML(html, options) {
  const stack = [];
  let index = 0;
  // 循环截取
  while (html) {
    let textEnd = html.indexOf("<");
    // 第一项
    if (textEnd === 0) {
      // 处理结束标签
      const endTagMatch = html.match(endTag);
      if (endTagMatch) {
        const curIndex = index;
        advance(endTagMatch[0].length);
        parseEndTag(endTagMatch[1], curIndex, index);
        continue;
      }
      // 处理开始标签
      const startTagMatch = parseStartTag();
      if (startTagMatch) {
        handleStartTag(startTagMatch);
        continue;
      }
    }

    let text, rest, next;
    if (textEnd >= 0) {
      rest = html.slice(textEnd);
      // console.log('html',html)
      // console.log('rest',rest)
      // console.log('textEnd',textEnd)
      // while (!endTag.test(rest) && startTagOpen.test(rest)) {
      //   next = rest.indexOf("<", 1);
      //   console.log('next',next)
      //   if (next < 0) break;
      //   textEnd += next;
      //   rest = html.slice(textEnd);
      // }
      text = html.substring(0, textEnd);
      // console.log('html',html)
      // console.log('textEnd',textEnd)
      // console.log('text',text)
    }
    if (textEnd < 0) {
      text = html;
    }
    if (text) {
      advance(text.length);
    }
    if (options.chars && text) {
      options.chars(text, index - text.length, index)
    }
  }
  // 截取字符串
  function advance(n) {
    index += n;
    html = html.substring(n);
    // console.log('html',html)
  }
  //
  function parseStartTag() {
    // debugger
    const start = html.match(startTagOpen);
    // 0: "<div" 1: "div"
    if (start) {
      const match = {
        tagName: start[1],
        attrs: [],
        start: index,
      };
      // advance 删除处理过的内容
      advance(start[0].length);
      // 处理属性
      // 是否能匹配到结束标签 如果匹配到 则没有其他属性
      let end, attr;
      //  没有匹配到startTagClose 并且 存在attr
      while (
        !(end = html.match(startTagClose)) &&
        (attr = html.match(dynamicArgAttribute) || html.match(attribute))
      ) {
        /**
         * 0: " id="app""
         * 1: "id"
         * 2: "="
         * 3: "app" // 双引号
         * 4: undefined // 单引号
         * 5: undefined // 无引号
         */
        attr.start = index;
        advance(attr[0].length);
        attr.end = index;
        match.attrs.push(attr);
      }
      if (end) {
        // match.unarySlash = end[1]
        advance(end[0].length);
        match.end = index;
        return match;
      }
    }
  }
  //
  function handleStartTag(match) {
    const tagName = match.tagName;
    // const unarySlash = match.unarySlash

    const l = match.attrs.length;
    const attrs = new Array(l);
    for (let i = 0; i < l; i++) {
      const args = match.attrs[i];
      const value = args[3] || args[4] || args[5] || ""; // 匹配值 双引号 单引号 无引号
      // 处理a标签 href
      attrs[i] = {
        name: args[1],
        value, // 对value进行修正 decodeAttr
      };
    }
    // todo 处理单标签 <br /> 等
    stack.push({tag:tagName,lowerCasedTag:tagName.toLowerCase(),attrs:attrs,start:match.start,end:match.end}) 
    if (options.start) {
      options.start(tagName, attrs, match.start, match.end);
    }
  }
  //
  function parseEndTag(tagName, start, end) {
    let pos,lowerCasedTagName
    if (start == null) start = index
    if (end == null) end = index

    if (tagName) {
      lowerCasedTagName = tagName.toLowerCase()
      for (pos = stack.length - 1; pos >= 0; pos--) {
        if (stack[pos].lowerCasedTag === lowerCasedTagName) {
          break
        }
      }
    }else {
      pos = 0
    }

    if(pos >= 0) {
      for (let i = stack.length - 1; i >= pos; i--) {
        if (options.end) {
          options.end(stack[i].tag, start, end)
        }
      }
      stack.length = pos
    }
  }
}
